#ifndef UTHREAD_H
#define UTHREAD_H

#include <unistd.h>
#include <setjmp.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
#include <assert.h>
#include <memory.h>
#include "list.h"
#include "mutex.h"
#include "thread.h"


typedef enum {RUNNABLE = 0, BLOCKED = 1, EXIT = 2} state_t;

#define STACKSIZE 	8192	// the stacksize of threads
#define MAX_NUM_THREADS 1024	// the maximum number of threads

#define MAIN		0
#define SCHEDULER	1

//type = 0 RUNNABLE_BLOCKED_LIST
//type = 1 JOINED_THREADS_LIST
#define RUNNABLE_BLOCKED_LIST 	0
#define JOINED_THREADS_LIST   	1
#define MUTEX_HLIST		2
#define COND_HLIST		3

/* defines for interacting with the thread context structure */

#define _BP 3
#define _SP 4
#define _PC 5

// the timeslice that we allocate for each thread 
// when do round-robin scheduling. Unit: microseconds
#define TIME_INTERVAL		2000

//this is the structure that stores the attributes of creating threads
typedef struct thread_attr
{
	int joinable;
} thread_attr;

//this is the identifier of each uthread
typedef int uthread_t;

typedef struct
{
	uthread_t id;       				// the thread_id
	thread_attr attr;				// the attributes for creating this thread
	state_t state;					// the state of the thread
	
	void * (*start)(void *);					// the start function of this thread
	void * args;					// the argument of this thread

#ifndef KERNEL_LEVEL_THREAD_EXTENSION
	jmp_buf context; 				// saved context the this user-level thread
#endif
	char stack[STACKSIZE];				// the size of the stack

	void * message;					// the message that this tcb has received from other tcbs.
	struct list_head joined_threads_list_head; 	// the head of a list which contains threads joined this thread. 
	uthread_spinlock_t joined_list_spinlock;	// When this thread exits, notify all joined threads
	struct list_head joined_threads_list;		// this represents a node in the joined_threads_list_head;
	
#ifndef KERNEL_LEVEL_THREAD_EXTENSION
	struct list_head runnable_blocked_list;		// this represents a node in the runnable_list
#endif
	struct hlist_node mutex_hlist;			// this represents a node in the mutex hlist
	struct hlist_node cond_hlist;			// this represents a condition hlist node

	void * exit_code;				// this field stores the exit code when this threads exits
	
#ifdef KERNEL_LEVEL_THREAD_EXTENSION
	thread_t kernel_thread_id;			// kernel thread id
#endif
} tcb_t;

extern int uthread_create(uthread_t * t, void* (*start)(void *), void * args);
extern int uthread_join(uthread_t &t, void ** status);
extern uthread_t uthread_self();
extern void uthread_exit(void * valptr);
extern void uthread_yield();

extern void switch_thread_state(uthread_t, state_t);
extern tcb_t * threads_table[MAX_NUM_THREADS];
extern void print_list(struct list_head * head, int type);
extern void print_hlist(struct hlist_head * head, int type);
#endif
